﻿/*******************************************************************************
* Copyright (C) JuCheap
* 
* Author: dj.wong
* Create Date: 09/04/2015 11:47:14
* Description: Automated building by service@jucheap.com 
* 
* Revision History:
* Date         Author               Description
*
*********************************************************************************/

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace JuCheap.Core.Infrastructure.Extentions
{
    /// <summary>
    ///     通用类型扩展方法类
    /// </summary>
    public static class ObjectExtensions
    {
        /// <summary>
        /// 获取对象的属性和值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GetKeyValue<T>(this T obj)
        {
            if (obj == null)
                return string.Empty;

            var sb = new StringBuilder();
            foreach (var prop in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var val = prop.GetValue(obj, null);
                var name = prop.Name;

                sb.AppendFormat("{0}={1}\r\n", name, val);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 反射实现同一个类的对象之间相同属性的值的复制
        /// 适用于没有新建实体之间
        /// </summary>
        /// <param name="target">返回的实体</param>
        /// <param name="source">数据源实体</param>
        /// <returns></returns>
        public static TIn CopyProperties<TIn>(this TIn source, TIn target)
        {
            var Types = source.GetType();//获得类型  
            var Typed = typeof(TIn);
            foreach (PropertyInfo sp in Types.GetProperties())//获得类型的属性字段  
            {
                foreach (PropertyInfo dp in Typed.GetProperties())
                {
                    if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType && dp.Name != "Error" && dp.Name != "Item")//判断属性名是否相同  
                    {
                        dp.SetValue(target, sp.GetValue(source, null), null);//获得s对象属性的值复制给d对象的属性  
                    }
                }
            }
            return target;
        }

        /// <summary>
        /// lambda表达式:t=>t.propName==propValue
        /// 多用于where条件
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="propName">属性名称</param>
        /// <param name="propValue">属性值</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> ToExpression<T>(this T model) where T : class
        {
            var type = typeof(T);
            // 创建节点参数t
            ParameterExpression parameter = Expression.Parameter(type, "t");
            Expression<Func<T, bool>> exps = null;
            var excludePropertyNames = new[]
            {
                "CreateTime",
                "ModifyTime",
                "IsDeleted",
                "PageIndex",
                "PageSize",
                "SortField",
                "SortType",
                "CompanyId",
                "Keywords"
            };
            var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            var properties = type.GetProperties().Where(x => !x.GetCustomAttributes<ExcludeField>().AnyOne() && !excludePropertyNames.Contains(x.Name));
            foreach(var property in properties)
            {
                var propertyValue = property.GetValue(model);
                if (propertyValue != null)
                {
                    // 创建一个成员(字段/属性)
                    MemberExpression member = Expression.PropertyOrField(parameter, property.Name);
                    // 创建一个常数
                    ConstantExpression constant = Expression.Constant(propertyValue);
                    // 创建一个相等比较Expression
                    Expression callExp;
                    if(property.PropertyType == typeof(string))
                    {
                        callExp = Expression.Call(member, containsMethod, constant);
                    }
                    else
                    {
                        callExp = Expression.Equal(member, constant);
                    }
                    // 生成lambda表达式
                    var exp = Expression.Lambda<Func<T, bool>>(callExp, parameter);
                    exps = exps == null ? exp : exps.And(exp);
                }
            }
            return exps;
        }
    }
}